package dd.lo.chapter5;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import org.opencv.core.Core;
import org.opencv.core.Core.MinMaxLocResult;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 对应练习示例
 * Create a mask using cv::compare(). Load a real image. Use cv::split() to split the image into red, green, and blue images.
 *   a. Find and display the green image.
 */
public class Example3 extends Application {
    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        //读取一张图片
        Mat srcImg = Imgcodecs.imread("/Users/kwok/Downloads/男女骑友.png", Imgcodecs.IMREAD_UNCHANGED);
        if (srcImg.empty()) {
            throw new RuntimeException("图片读取失败");
        }
        int w = srcImg.width(), h = srcImg.height();
        //Channels arranged in BGR
        List<Mat> channels = new ArrayList<>(3);
        //Split channels
        Core.split(srcImg, channels);
        //Clone this green plane image twice (call these clone1 and clone2)
        Mat greenPlane = channels.get(1);
        Mat clone1 = greenPlane.clone();
        Mat clone2 = greenPlane.clone();
        //Find the green plane’s minimum and maximum value.
        MinMaxLocResult minMaxLocResult = Core.minMaxLoc(greenPlane);
        //Set clone1’s values to thresh = (unsigned char)((maximum - minimum)/2.0)
        double threshold = (minMaxLocResult.maxVal - minMaxLocResult.minVal) / 2.0;
        clone1.setTo(new Scalar(threshold));
        //Set clone2 to 0 and use cv::compare (green_image, clone1, clone2, cv::CMP_GE). Now clone2 will have a mask of where the value exceeds threshold in the green image
        clone2.setTo(new Scalar(0));
        Core.compare(greenPlane, clone1, clone2, Core.CMP_GE);
        //Finally, use cv::subtract (green_image,thresh/2, green_image, clone2) and display the results.
        Core.subtract(greenPlane, new Scalar(threshold / 2.0), greenPlane, clone2);
        //Show source image
        ImageView imageView = new ImageView();
        imageView.setFitWidth(w);
        imageView.setFitHeight(h);
        MatOfByte buffer = new MatOfByte();
        Imgcodecs.imencode(".jpeg", srcImg, buffer);
        imageView.setImage(new Image(new ByteArrayInputStream(buffer.toArray())));
        //imageView放到一个pane的中间
        BorderPane root = new BorderPane();
        root.setCenter(imageView);
        Scene scene = new Scene(root, srcImg.width(), srcImg.height());
        scene.setOnKeyReleased(keyEvent -> {
            //按下esc可以关闭程序
            if (KeyCode.ESCAPE == keyEvent.getCode()) {
                stage.close();
            }
        });
        stage.setScene(scene);
        stage.setTitle("Example3-Mask using cv::compare()");
        stage.setResizable(false);
        stage.show();
//        Platform.runLater(() -> showImgNewWindow(channels.get(0), "Example3-Channel Blue"));
        Platform.runLater(() -> showImgNewWindow(greenPlane, "Example3-Channel Green"));
//        Platform.runLater(() -> showImgNewWindow(channels.get(2), "Example3-Channel Red"));
        Platform.runLater(() -> showImgNewWindow(clone2, "Example3-Channel Green Clone 2"));
    }

    private void showImgNewWindow(Mat img, String windowName) {
        MatOfByte buffer = new MatOfByte();
        Imgcodecs.imencode(".jpeg", img, buffer);
        ImageView imageView = new ImageView();
        imageView.setImage(new Image(new ByteArrayInputStream(buffer.toArray())));
        BorderPane root = new BorderPane();
        root.setCenter(imageView);
        Scene scene = new Scene(root, img.width(), img.height());
        Stage stage = new Stage();
        stage.setScene(scene);
        stage.setTitle(windowName);
        stage.setResizable(false);
        stage.show();
    }
}
